#include <sys/epoll.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

#define PORT 5555
#define NUM 20

int main(int argc, char** argv)
{
	int sfd,cfd;
	struct sockaddr_in saddr,caddr;
	socklen_t caddrlen = sizeof(caddr);
	memset(&saddr, 0, INET_ADDRSTRLEN);

	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(PORT);
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);

	sfd = socket(AF_INET, SOCK_STREAM, 0);
	
	int opt = 1;
	setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	bind(sfd, (struct sockaddr *)&saddr, INET_ADDRSTRLEN);

	listen(sfd, 5);

	struct epoll_event ev, events[NUM];
	ev.events = EPOLLIN;
	ev.data.fd = sfd;
	
	int efd = epoll_create(NUM);

	epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &ev);
	
	ev.events = EPOLLIN;
	ev.data.fd = STDIN_FILENO;
	epoll_ctl(efd, EPOLL_CTL_ADD, STDIN_FILENO, &ev);

	char buf[BUFSIZ];

	int epollfd[NUM] = {[0 ...(NUM-1)] = -1};	
	

	while(1)
	{
		int nready = epoll_wait(efd, events, NUM, -1);
		
		for(int i = 0; i<nready; i++)
		{
			if((events[i].events & EPOLLIN) && (events[i].data.fd == sfd))
			{
				printf("456");
				cfd = accept(sfd, (struct sockaddr*)&caddr, &caddrlen);
				
				ev.events = EPOLLIN;
				ev.data.fd = cfd;
				epoll_ctl(efd, EPOLL_CTL_ADD, cfd, &ev);				
				
				for(int j = 0; j < NUM; j++)
				{
					if(epollfd[j] != -1)
					{
						epollfd[j] = cfd;
						break;
					}
				}	
			}
			else if((events[i].events & EPOLLIN) && (events[i].data.fd == STDIN_FILENO))
			{
				printf("123");
				int ret = read(STDIN_FILENO, buf, sizeof(buf));
				
				for(int j = 0; j < NUM; j++)
				{
					if(epollfd[j] != -1)
					{
						write(epollfd[j], buf, ret);					
					}
				}
			}
			else if(events[i].events & EPOLLIN)
			{
				printf("789");
				int sockfd = events[i].data.fd;
				int ret = read(sockfd, buf, sizeof(buf));
				if(ret == 0)
				{
					printf("a socket is closed.\n");
					epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL);
					for(int j = 0; j < NUM; j++)
					{
						if(epollfd[j] == sockfd)
						{
							epollfd[j] = -1;
							break;
						}
					}					
					continue;
				}
				write(STDOUT_FILENO, buf, ret);
			}
		}
	}

	return 0;
}
